using System;
using System.Dynamic;
using System.IO;
using System.Web.Mvc;
using System.Xml;
using System.Xml.Xsl;
using ABC.Mvc;
using Mvp.Xml.Common.Xsl;
using ABC.XPath;

namespace ABC.XsltEngine
{
	public class XsltView : IView
	{
		private readonly MvpXslTransform _transform;
		private readonly XmlResolver _resolver;

		public XsltView( MvpXslTransform transform, XmlResolver resolver )
		{
			_transform = transform;
			_resolver = resolver;
		}

		public void Render( ViewContext viewContext, TextWriter writer )
		{
			var args = new XsltArgumentList();
			args.AddExtensionObject( "urn:HtmlHelper",
				new HtmlHelperAdapter( new HtmlHelper( viewContext, new ViewDataContainer( viewContext.ViewData ) ) ) );
			
			var data = GetXPathContext().CreateNavigator( viewContext.ViewData );
			_transform.Transform( new XmlInput( data, _resolver ), args, new XmlOutput( writer ) );
		}

		private ObjectXPathContext GetXPathContext()
		{
			var ctx = new ObjectXPathContext();

			ctx.NamespaceManager.AddNamespace( "sdf", Namespaces.ABC );
			ctx.DetectLoops = _resolver != null;
			ctx.LoopDetected += ( ( sender, e ) =>
			{
				throw new Exception( string.Format( "Loop detected: Stack {0}\r\nNode: {1}\r\nPath: {2}",
				                                    e.Navigator.GetNavigationStack(), e.Node.Object,
				                                    e.Navigator.GetCurrentNodePath() ) );
			} );

			ctx.RegisterNodePolicy( typeof( ViewDataDictionary ), typeof( ViewDataNodePolicy ) );
			ctx.RegisterNodePolicy( typeof( ExpandoObject ), typeof( ExpandoObjectNodePolicy ) );
			
			return ctx;
		}
	}
}